#include "scrollbar.h"

ScrollBar::ScrollBar(std::string id, int x, int y, int size_x, int size_y, float step,
		int button_height, int slider_padding, std::string slider_background_graphic, int slider_height,
		std::string slider_graphic_up, std::string slider_graphic_down, std::string button_graphic_top_up,
		std::string button_graphic_top_down, std::string button_graphic_bottom_up,
		std::string button_graphic_bottom_down)
	: GuiElement(id, x, y, size_x, size_y)
{
	m_slider_height = slider_height;
	m_step = step;
	m_slider_padding = slider_padding;
	m_slider_background_graphic = slider_background_graphic;
	m_slider_graphic_up = slider_graphic_up;
	m_slider_graphic_down = slider_graphic_down;
	m_button_height = button_height;
	m_button_graphic_top_up = button_graphic_top_up;
	m_button_graphic_top_down = button_graphic_top_down;
	m_button_graphic_bottom_up = button_graphic_bottom_up;
	m_button_graphic_bottom_down = button_graphic_bottom_down;

	// Create the buttons.
	m_top_button = new Button(m_id + "_top_button", m_x, m_y, m_size_x, m_button_height,
		std::bind([this](){ ChangeValue(m_value - m_step); }), m_button_graphic_top_up, m_button_graphic_top_down);
	m_bottom_button = new Button(m_id + "_bottom_button", m_x, m_y + m_size_y - m_button_height, m_size_x,
		m_button_height, std::bind([this](){ ChangeValue(m_value + m_step); }),
		m_button_graphic_bottom_up, m_button_graphic_bottom_down);

	// Initial value of the slider.
	m_value = 0.0f;
	m_slider_position = m_y + m_button_height + m_slider_padding;
	m_grabbed = false;
}

ScrollBar::~ScrollBar()
{
	delete m_top_button;
	delete m_bottom_button;
}

void ScrollBar::ScrollToBottom()
{
	ChangeValue(1.0f);
}

void ScrollBar::ChangeValue(float value)
{
	// Make sure we stay in range.
	if (value < 0.0f) value = 0.0f;
	if (value > 1.0f) value = 1.0f;

	// The position most in the top and most in the bottom of the slider.
	int slider_top = m_y + m_button_height + m_slider_padding;
	int slider_bottom = m_y + m_size_y - m_button_height - m_slider_padding - m_slider_height;

	// Change the position of the slider and the value.
	m_slider_position = slider_top + value * (slider_bottom - slider_top);
	m_value = value;
}

void ScrollBar::PrimaryMouseButtonUp(int x, int y)
{
	m_grabbed = false;

	m_top_button->PrimaryMouseButtonUp(x, y);
	m_bottom_button->PrimaryMouseButtonUp(x, y);
}

void ScrollBar::PrimaryMouseButtonDown(int x, int y)
{
	// Did we hit the slider?
	bool hit = false;
	if (x >= m_x + m_slider_padding && x < m_x + m_size_x - m_slider_padding && y >= m_slider_position &&
		y < m_slider_position + m_slider_height)
		hit = true;

	// If yes it is now grabbed.
	if (hit)
	{
		m_grabbed = true;
		m_grab_position = y;
	}

	m_top_button->PrimaryMouseButtonDown(x, y);
	m_bottom_button->PrimaryMouseButtonDown(x, y);
}

void ScrollBar::MouseAxisChange(int x, int y)
{
	// If we have grabbed the slider and moved the mouse vertically, we need to move the slider and update
	// the value.
	if (m_grabbed && y != m_grab_position)
	{
		// How much was the slider moved since the last event?
		m_slider_position += y - m_grab_position;
		m_grab_position = y;

		// The position most in the top and most in the bottom of the slider.
		int slider_top = m_y + m_button_height + m_slider_padding;
		int slider_bottom = m_y + m_size_y - m_button_height - m_slider_padding - m_slider_height;

		// Make sure the slider does not leave the bar.
		if (m_slider_position > slider_bottom) m_slider_position = slider_bottom;
		if (m_slider_position < slider_top) m_slider_position = slider_top;
		if (m_grab_position > slider_bottom + m_slider_height) m_grab_position = slider_bottom + m_slider_height;
		if (m_grab_position < slider_top) m_grab_position = slider_top;

		// Update the value.
		m_value = (float)(m_slider_position - slider_top) / (float)(slider_bottom - slider_top);
	}
}

void ScrollBar::Update()
{
	m_top_button->Update();
	m_bottom_button->Update();
}

void ScrollBar::Draw()
{
	// Draw the background.
	ALLEGRO_BITMAP* graphic = allegro_bitmap_resource_manager.GetResource(m_slider_background_graphic);
	al_draw_scaled_bitmap(graphic, 0, 0, al_get_bitmap_width(graphic), al_get_bitmap_height(graphic),
		m_x, m_y + m_button_height, m_size_x, m_size_y - 2 * m_button_height, NULL);

	// Show right graphic based on whether we have clicked the slider or not.
	if (m_grabbed)
	{
		graphic =  allegro_bitmap_resource_manager.GetResource(m_slider_graphic_down);
		al_draw_scaled_bitmap(graphic, 0, 0, al_get_bitmap_width(graphic), al_get_bitmap_height(graphic),
			m_x + m_slider_padding, m_slider_position, m_size_x - 2 * m_slider_padding, m_slider_height, NULL);
	}
	else
	{
		graphic =  allegro_bitmap_resource_manager.GetResource(m_slider_graphic_up);
		al_draw_scaled_bitmap(graphic, 0, 0, al_get_bitmap_width(graphic), al_get_bitmap_height(graphic),
			m_x + m_slider_padding, m_slider_position, m_size_x - 2 * m_slider_padding, m_slider_height, NULL);
	}

	m_top_button->Draw();
	m_bottom_button->Draw();
}